/*************************************************************************
|                                                                        |
|   MAKE.C                                                      12.06.93 |
|   ADMAKE Utility:  do the actual making                                |
|                                                                        |
*************************************************************************/

#ifdef VMS
#include STDIO
#include PROCESSES
#include ERRNO
#include CTYPE
#include STRING
#include STDLIB
#include TYPES
#include STAT
#include "h.h"
#endif

#ifdef NIX
#include <stdio.h>
#include <fcntl.h>
#include "h.h"
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#ifndef PKILL
#define PKILL 0
#endif
#endif

#ifdef __BORLANDC__
#include <stdio.h>
#include <fcntl.h>
#include <dos.h>
#include <io.h>
#include "h.h"
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <process.h>
#if (__BORLANDC__ < 0x0400)
#include <dir.h>
#define _getdrive() (getdisk()+1)
#define _chdrive(x) setdisk(x - 1)
#else
#include <direct.h>
#endif
#endif

#ifdef _MSC_VER
#include <stdio.h>
#include <io.h>
#include <process.h>
#include <dos.h>
#include "h.h"
#include <errno.h>
#include <ctype.h>
#include <string.h>
#ifdef HEAP
#include <heap.h>
#endif
#include <stdlib.h>
#include <malloc.h>
#include <direct.h>
#endif

#ifdef _INTELC32_
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <process.h>
#include <dos.h>
#include "h.h"
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <direct.h>
#endif

#ifdef __ZTC__
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <process.h>
#include <dos.h>
#include "h.h"
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <process.h>
#include <direct.h>
static unsigned maxdrives;
#endif

#ifdef __WATCOMC__
#include <stdio.h>
#include <dos.h>
#include <io.h>
#include <direct.h>
#include <h.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <process.h>
#include <malloc.h>
static unsigned maxdrives;
#endif

#define ARGN 64

static int  lifmade = 0;
static char lifname[128] = "";

struct path *    pathhead;

#ifdef DOLLAR
static char dollarbuf[LZ];
#endif

#ifdef PAMDOS
#define TESTINTERNAL 8      /* number of internal commands to test for */ 
#define REDIRECT 1          /* do our own redirection */
#endif

#ifdef PAMOS2
#define TESTINTERNAL 8      /* number of internal commands to test for */ 
#define REDIRECT 1          /* do our own redirection */
#endif

                            /* Dos internal commands, augment list if reqd */
#ifdef TESTINTERNAL
static char * internal[] =
{
    "ECHO",
    "DEL",
    "ERASE",
    "MD",
    "MKDIR",
    "REN",
    "RENAME",
    "COPY",
};
#endif

#ifdef DOLLAR

/*************************************************************************
|                                                                        |
|   >>>>  dollar                                                         |
|                                                                        |
|   remove special $ markers                                             |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD 
char * dollar(char * p)
#else
char * dollar(p)
char * p;
#endif

{
    register char *         q = dollarbuf;
    
    while (*p)
    {
        if ((*p & 0xff) == 0244) 
        {
            *q++ = '$';
            p++;
        }
        else *q++ = *p++;
    }
    *q = '\0';
    return dollarbuf;
}

#endif


#ifdef REDIRECT

/*************************************************************************
|                                                                        |
|   dos_internal                                                         |
|                                                                        |
|   test for common DOS and OS/2 internal commands, true if found        |
|                                                                        |
*************************************************************************/

#if PANEWFD
static int dos_internal(char * s)
#else 
static int dos_internal(s)
char * s;
#endif

{
    register int            i;
    char *                  p;
    char *                  q;

    while ((*s == ' ') && (*s != '\0')) s++;
    for (i = 0; i < TESTINTERNAL; i++)
    {
        p = s;
        q = internal[i];
        while ( (*p != ' ') && ( (*p & 0x5f) == *q )) p++,q++;
        if ((*p == ' ') && (*q == '\0')) return 1;
    }
    return 0;
}

/*************************************************************************
|                                                                        |
|   dos_cdd                                                              |
|                                                                        |
|   test for DOS and OS/2 change drive or dir, true if found             |
|                                                                        |
*************************************************************************/

#if PANEWFD
static int dos_cdd(char * s)
#else 
static int dos_cdd(s)
char * s;
#endif

{
    while ((*s == ' ') && (*s != '\0')) s++;
    if (((*s & 0x5f) >= 'A') &&
        ((*s & 0x5f) <= 'Z') &&
        (*(s + 1) == ':') &&
        ((*(s + 2) == ' ') || (*(s + 2) == '\0')))
    {
#ifdef __ZTC__
        dos_setdrive((*s & 0x5f) - 'A' + 1,&maxdrives);
        dos_getdrive(&maxdrives);
        if (maxdrives != ((*s & 0x5f) - 'A' + 1))
            fatal(MSG[52]);             /* unable to change drive */
#else        
#ifdef __WATCOMC__
        _dos_setdrive((*s & 0x5f) - 'A' + 1,&maxdrives);
        _dos_getdrive(&maxdrives);
        if (maxdrives != ((*s & 0x5f) - 'A' + 1))
            fatal(MSG[52]);             /* unable to change drive */
#else
        _chdrive((*s & 0x5f) - 'A' + 1);
        if (_getdrive() != ((*s & 0x5f) - 'A' + 1))
            fatal(MSG[52]);             /* unable to change drive */
#endif
#endif
        return 1;
    }

    if (((*s & 0x5f) == 'C') &&
        ((*(s + 1) & 0x5f) == 'D') &&
        (*(s + 2) == ' '))
    {
        s += 3;
        while ((*s == ' ') && (*s != '\0')) s++;
        if (chdir(s))
        {
            fatal(MSG[53]);     /* couldn't change directory */
        }
        return 1;
    }
    return 0;
}

#endif

/*************************************************************************
|                                                                        |
|   >>>>  dosh                                                           |
|                                                                        |
|   do the command                                                       |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static int dosh(char * p, int shell)
#else 
static int dosh(p, shell)
char * p;
int shell;
#endif

{
#ifdef VMS

    int                     result;

    result = 0xffff & system(dollar(p));
    if (result == 33384) return 0;      /* LINK: compilation warnings */
    if (result == PXNORMAL) return 0;
    return result;
    
#else

#ifdef NIX

    int                     result;
    int                     resh,resl;

    result = system(dollar(p));
    resl = result & 0xff;
    resh = (result >> 8) & 0xff;
    if (result == 0) return 0;
    if (result == PKILL) return 4;
    if ((resl == 0x7f) || (resh == 0x7f)) return -1;
    if ((resl == SIGINT) || (resl == SIGKILL)) return 4;
    return resh;

#else

    int                     argc;
    char *                  argv[ARGN];
    char                    c;
    int                     ret;
#ifdef REDIRECT
    int                     mode;
    char *                  q;
    int                     r0,r1,r2;     
    char                    token[64];
    register int            i;
#endif

    p = dollar(p);
    if (shell) return system(p);

#ifdef REDIRECT             /* must be DOS or OS/2 */

    r0 = r1 = r2 = -1;      /* clear redirection switches */

    ret = 999;
    if ((q = pstrstr(p,"<")) != (char *)0)
    {
        i = 0;
        *q++ = ' ';
        while (*q == ' ') q++;
        while (!pspace(*q) && (*q != '\0') && (i < 63))
        {
            token[i++] = *q;
            *q++ = ' ';
        }
        token[i] = '\0';
        r0 = dup(fileno(stdin));
        if (NULL == freopen(token,"r",stdin)) goto done;
    }
    if (((q = pstrstr(p,"2>")) != (char *)0) ||
        ((q = pstrstr(p,">&")) != (char *)0))
    {
        i = mode = 0;
        *q++ = ' ';
        *q++ = ' ';
        if (*q == '>')
        {
            mode = 1;
            *q++ = ' ';
        }
        while (*q == ' ') q++;
        while (!pspace(*q) && (*q != '\0') && (i < 63))
        {
            token[i++] = *q;
            *q++ = ' ';
        }
        token[i] = '\0';
        fflush(stderr);
        r2 = dup(fileno(stderr));
        if (NULL == freopen(token,((mode)?"a":"w"),stderr)) goto done;
        if (mode) fseek(stderr,0L,2);
    }
    if ((q = pstrstr(p,">")) != (char *)0)
    {
        mode = i = 0;
        *q++ = ' ';
        if (*q == '>')
        {
            mode = 1;
            *q++ = ' ';
        }
        while (*q == ' ') q++;
        while (!pspace(*q) && (*q != '\0') && (i < 63))
        {
            token[i++] = *q;
            *q++ = ' ';
        }
        token[i] = '\0';
        fflush(stdout);
        r1 = dup(fileno(stdout));
        if (NULL == freopen(token,((mode)?"a":"w"),stdout)) goto done;
        if (mode) fseek(stdout,0L,2);
    }

#endif

#ifdef SWAPEXEC
    if (swap)
        ;
    else
#endif
    {
        for (argc = 0; argc < ARGN-1; argc++) argv[argc] = 0;
        for (argc = 0; argc < ARGN-1; )
        {
            while(pspace(*p)) p++;
            if (*p == '\0') break;
            argv[argc++] = p;
            while ((*p != '\0') && (! pspace(*p))) p++;
            c = *p;
            *p++ = '\0';
            if (c == '\0') break;
        }
    }

#ifdef MSC6
#ifdef HEAP
    _heappack();
#else
    _heapmin();
#endif
#endif

#ifdef __WATCOMC__
    _heapshrink();
#endif

#ifdef _INTELC32_
    _heapmin();
#endif

#ifdef SWAPEXEC

    if (swap)
    {
        while(pspace(*p)) p++;
        i = 0;
        while ((!(pspace(*p))) && (*p != '\0') && (i < 64)) token[i++] = *p++;
        token[i] = '\0';
        while(pspace(*p)) p++;
        ret = do_exec(token,p,USE_ALL+HIDE_FILE+CHECK_NET,0xffff,environ);
        if (ret > 0xff)
        {
            ret = -1;
        }
    }
    else

#endif

    {
        fflush(stdout);
        fflush(stderr);
        /*lint -e771 */
#ifdef __ZTC__
        ret = spawnvp(P_WAIT,argv[0],(const char * const *)argv);
#else
        ret = spawnvp(P_WAIT,argv[0],argv);
#endif
        /*lint -restore */
    }

#ifdef REDIRECT

done:

    if (r0 > -1) {dup2(r0,fileno(stdin));  close(r0);}
    if (r1 > -1) {fflush(stdout); dup2(r1,fileno(stdout));  close(r1);}
    if (r2 > -1) {fflush(stderr); dup2(r2,fileno(stderr));  close(r2);}

#endif
    return ret;

#endif
#endif

}

/*************************************************************************
|                                                                        |
|   >>>>  makelif                                                        |
|                                                                        |
|   create the local input file                                          |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static VOID makelif(struct cmd * cp)
#else
static VOID makelif(cp)
struct cmd * cp;
#endif

{
    FILE *                  lifile;
    struct lif *            lp;
    struct macro *          mp;
    char *                  p = lifname;
    char *                  q;

    lifmade = 0;
    if ( cp->c_lif == (struct lif *)0 ) return;
    if ((mp = getmp("-")) != (struct macro *)0)
    {
        if (mp->m_sub) 
        {
            strncpy(lifname,mp->m_sub,127);
            free(mp->m_sub);
        }
        else 
            strncpy(lifname,mp->m_val,127);
    }
    else
        lifname[0] = '\0';
    while (*p == ' ') p++;
#ifdef DOLLAR
    strcpy(lifname,dollar(lifname));
#endif
    if (*p == '\0') strcpy(lifname,LIFNAME);
    if ( (lifile = fopen(lifname,"w")) == NULL) fatal(MSG[54]);
    for (lp = cp->c_lif; lp; lp = lp->f_next)
    {
        initml(1,lp->f_lif);
        while ((makeml(1)) != 0) 
        {
            strcpy(str2, lp->f_lif);
            expand(str2);
        
            /* replace newlines in lif line with spaces */
        
            for (q = str2; ((q = strchr(q,'\n')) != (char *)0); q++) *q = ' ';
            if (!strcmp(str2,"\\<")) strcpy(str2,"<");
        
            /* allow \\n to represent \n as well as \n representing newline */
        
            p = str2;
            while ((q = pstrstr(p,"\\n")) != (char *)0)
            {
                if (*(q-1) == '\\')
                {
                    p = q + 2;
                    while (*++q) *(q - 1) = *q;
                    *--q = '\0';
                    p--;
                    continue;
                }
                p = q;
                *q++ = '\n';
                while (*++q) *(q-1) = *q;
                *--q = '\0';
            }
            if (*str2 == '\0')
            {
                if (fputs(" ",lifile) == EOF) fatal(MSG[54]);
            }
            else
            {
                if (fputs(dollar(str2),lifile) == EOF) fatal(MSG[54]);
            }
            if (fputs("\n",lifile) == EOF) fatal(MSG[54]);
        }
    }
    if (fclose(lifile) == EOF) fatal(MSG[54]);
    lifmade = 1;
}

/*************************************************************************
|                                                                        |
|   >>>>  killlif                                                        |
|                                                                        |
|   kill the local input file                                            |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static VOID killlif(void)
#else
static VOID killlif()
#endif

{
    if (lifmade) unlink(lifname);
}


/*************************************************************************
|                                                                        |
|   >>>>  dosetcmd                                                       |
|                                                                        |
|   do the %set command                                                  |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static VOID dosetcmd(char * p)
#else
static VOID dosetcmd(p)
char * p;
#endif

{
    char *                  q;
    char *                  pp;

    while (pspace(*p)) p++;    /* find first target */

    pp = p;
    while (((q = strchr(p, '=')) != (char *)0) &&
        (p != q) && (q[-1] == '\\'))        /*  Find value */
    {
        register char * a;

        a = q - 1;              /* del \ chr; move rest back */
        p = q;
        while ((*a++ = *q++) != '\0') ;
    }

    if (q != (char *)0)
    {
        register char * a;

        *q++ = '\0';            /* separate name and val */
        while (pspace(*q)) q++;
        if ((a = gettok(&pp)) == (char *)0)
            error(MSG[38]);     /* macro def without macro name */
        setmacro(a, q);
    }
}

/*************************************************************************
|                                                                        |
|   >>>>  dostatcmd                                                      |
|                                                                        |
|   do the %stat command                                                 |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static VOID dostatcmd(char * p)
#else
static VOID dostatcmd(p)
char * p;
#endif

{
    struct name *           q;

    while (pspace(*p)) p++;    /* find filename */
    q = newname(p);
    if (q->n_flag & N_TARG)
    {
        q->n_flag &= ~N_TSNAP;
        searchtime(q);
        q->n_flag &= ~N_DONE;
    }
}

/*************************************************************************
|                                                                        |
|   >>>>  docmds1                                                        |
|                                                                        |
|   do a command to make a target                                        |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static void docmds1(struct name * np, struct line * lp)
#else
static void docmds1(np, lp)
struct name * np;
struct line * lp;
#endif

{
    bool                    ssilent;
    bool                    signore;
    bool                    sdomake;
    int                     estat;
    register char *         q;
    register char *         p;
    int                     shell;
    register struct cmd *   cp;
    int                     specialhash;

    for (cp = lp->l_cmd; cp; cp = cp->c_next)
    {
        if (why)
        {
            struct lif * llp;

            printf("    %s\n",cp->c_cmd);
            for (llp = cp->c_lif; llp; llp = llp->f_next)
                printf("        %s\n",llp->f_lif);
        }
        shell = 0;
        ssilent = silent;
        signore = ignore;
        sdomake = domake;
        strcpy(str1, cp->c_cmd);

        if (!strncmp(str1,"%iferr",6)) specialhash = H_IFERR;
        else if (!strncmp(str1,"%ife",4)) specialhash = H_IFE;
        else if (!strncmp(str1,"%ifne",5)) specialhash = H_IFNE;
        else if (!strncmp(str1,"%ifn",4)) specialhash = H_IFN;
        else if (!strncmp(str1,"%if",3)) specialhash = H_IF;
        else if (!strncmp(str1,"%else",5)) specialhash = H_ELSE;
        else if (!strncmp(str1,"%endif",6)) specialhash = H_ENDIF;
        else if (!strncmp(str1,"%set",4)) specialhash = H_SET;
        else if (!strncmp(str1,"%exitnr",7)) specialhash = H_ABORTEXITNR;
        else if (!strncmp(str1,"%exit",5)) specialhash = H_ABORTEXIT;
        else if (!strncmp(str1,"%stat",5)) specialhash = H_STAT;
        else specialhash = H_NONE;

        if (ifproc(str1,specialhash)) continue;
        if (specialhash == H_ABORTEXITNR) exit(atoi(str1+7));
        if (specialhash == H_ABORTEXIT) 
        {
            resetcd();
            exit(atoi(str1+5));
        }
        if (specialhash == H_SET)
        {
            dosetcmd(str1+4);
            continue;
        }
        if (specialhash == H_STAT)
        {
            dostatcmd(str1+5);
            continue;
        }

        initml(0,cp->c_cmd);
        while (makeml(0) != 0) 
        {
            if (pstrstr(str1,"$(MAKE)")) sdomake = TRUE;
            strcpy(str1, cp->c_cmd);
            expand(str1);
            q = str1;
            while ((*q == '@') || (*q == '-') || (*q == '+') || (*q == '\\'))
            {
                if (*q == '@') ssilent = TRUE;      /* specific silent */
                else if (*q == '-') signore = TRUE; /* specific ignore */
                else if (*q == '+') shell = 1;      /* specific shell */
                else                                /* must be \ */
                {
                    q++;                            /* skip past \ */
                    if ((*q == '@') || (*q == '-') || (*q == '+')) break;
                    else                            /* \ is a real char */
                    {
                        q--;                        /* make it start command */
                        break;                      /* no more specials */
                    }
                }
                q++;                                /* skip past special char */
            }
#ifdef TESTINTERNAL
            if ( dos_internal(q) ) shell = 1;
#endif

            if (!ssilent) fputs("    ", stdout);

            for (p = q; *p; p++)
            {
                if (*p == '\n' && p[1] != '\0')
                {
                    *p = ' ';
                    if (!ssilent) fputs("\\\n", stdout);
                }
                else if (!ssilent)
                {
#ifdef DOLLAR
                    if ((*p & 0xff) == 0244) 
                        putchar('$');
                    else
#endif
                        putchar(*p);
                }
            }
            if (!ssilent) putchar('\n');

#ifdef TESTINTERNAL
            if ( dos_cdd(q) ) continue;
#endif

#ifdef _HEAPDEBUG
            printf (MSG[55],_heapchk());
#endif

            if (sdomake)
            {                       /*  Get the shell to execute it  */
                makelif(cp);
                estat = dosh(q, shell);
                errorlevel = (unsigned int)estat;
                killlif();
#ifdef PAMDOS
                bdos(0xb,0,0);    /* check control break */
#endif
                if (estat != 0)
                {
                    if (shell)
                    {
/* ignored */           if (ignoreshell & signore) fputs(MSG[56],stdout);
/* cannot shell*/       else fatal(MSG[57],estat,errno);
                    }
                    else
                    {
/* interrupted */       if (estat==4) printf(MSG[58], myname);
/* cannot exec */       else if (estat==-1) printf(MSG[59],myname,errno);
/* redir error */       else if (estat==999) printf(MSG[60],myname,errno);
/* error return */      else printf(MSG[61], myname, estat);
/* ignored */           if ( (signore || !domake) && (estat != 4)) fputs(MSG[56], stdout);
                        else 
                        {
                            putchar('\n');
                            if (!(np->n_flag & N_PREC) && (estat != -1))
                            {
                                if (unlink(dollar(np->n_name)) == 0)
/* removed */                       printf(MSG[62], myname, dollar(np->n_name));
                            }    
                            resetcd();
                            exit(estat);
                        }
                    }
                }
            }
        }
    }
    ifeoc();         /* check for unterminated if in cmds */
}

/*************************************************************************
|                                                                        |
|   >>>>  docmds                                                         |
|                                                                        |
|   do a set of commands to make a target                                |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static void docmds(struct name * np)
#else
static void docmds(np)
struct name * np;
#endif

{
    struct name *           dft;
    register struct line *  rp;
    struct line *           lp;
    bool                    hascmds = FALSE;

    for
        (
        rp = np->n_line;
        rp;
        rp = rp->l_next
        )
        if (rp->l_cmd) hascmds = TRUE;

    if (!hascmds)
    {
        dft = newname(".DEFAULT");
        if (dft->n_flag & N_TARG) np->n_line = dft->n_line;
    }

    for (lp = np->n_line; lp; lp = lp->l_next)
        docmds1(np,lp);
}

/*************************************************************************
|                                                                        |
|   >>>>  psa                                                            |
|                                                                        |
|   string append, faster than strcat for successive appends             |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
char * psa(char * target, char * source)
#else
char * psa(target, source)
char * target;
char * source;
#endif

{
    while ((*target++ = *source++) != '\0')  ;
    return (target-1);
}

/*************************************************************************
|                                                                        |
|   >>>>  setdmacros                                                     |
|                                                                        |
|   set $< and $* for the first dependency name                          |
|   set $? to list of out-of-date dependency names                       |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static VOID setdmacros(struct name * np, struct depend * qdp)
#else 
static VOID setdmacros(np, qdp)
struct name * np;
struct depend * qdp;
#endif

{
    char *                  p;
    char *                  q;
    char *                  pp;
    char *                  suff;
    struct depend *         sdp = qdp;
    register struct depend *dp;
    register struct line *  lp;
    int                     found = 0;
    int                     l = 0;

    p = str1;
    q = str2;
    *p = *q = '\0';
    for (dp = qdp; dp; dp = qdp)
    {
        l += strlen(pp = dp->d_name->n_name) + 3;
        if (l > LZ) fatal(MSG[63]);     /* $? macro is too long */
        if (p > str1) p = psa(p," ");
        p = psa(p,pp);
        q = psa(q,pp);
        q = psa(q,"\\n");
        qdp = dp->d_next;
        if ((!why) || (!(np->n_flag & N_TARG))) free(dp);
    }
    setmacro("?", str1);
    setmacro("|", str2);

    if ((why) && (np->n_flag & N_TARG))
    {
        printf(MSG[64]);                /* Make target: */
        dodisp(np->n_name,np->n_time);
        printf(MSG[65]);                /* Newer files are:\n */
        for (dp = sdp; dp; dp = sdp)
        {
            dodisp(dp->d_name->n_name, dp->d_name->n_time);
            sdp = dp->d_next;
            free(dp);
        }
        printf("\n");    
    }

    for (lp = np->n_line; lp; lp = lp->l_next)
        for (dp = lp->l_dep; dp; dp = dp->d_next)
        {
            if ( (!found) || (dp->d_name->n_flag & N_DYND) )
            {
                q = dp->d_name->n_name;
                setmacro("<",q);
                p = str1;
                suff = suffix(q);
                while (q < suff) *p++ = *q++;
                *p = '\0';
                setmacro("*",str1);
                if (found) return;
                found++;
            }
        }
}

/*************************************************************************
|                                                                        |
|   >>>>  cleardynflag                                                   |
|                                                                        |
|   clear the dynamic dep flag for all deps of this target               |
|   (in case this dep is used again for another target)                  |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static VOID cleardynflag(struct name * np)
#else
static VOID cleardynflag(np)
struct name * np;
#endif

{
    register struct depend *dp;
    register struct line *  lp;

    for (lp = np->n_line; lp; lp = lp->l_next)
        for (dp = lp->l_dep; dp; dp = dp->d_next)
            dp->d_name->n_flag &= ~N_DYND;
}

/*************************************************************************
|                                                                        |
|   >>>>  make1                                                          |
|                                                                        |
|   make one thing                                                       |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static VOID make1(struct name * np, struct line * lp, struct depend * qdp)
#else
static VOID make1(np, lp, qdp)
struct name * np;
struct line * lp;
struct depend * qdp;
#endif

{
    register struct line *  rp;
    bool                    hascmds = FALSE;

    for
        (
        rp = np->n_line;
        rp;
        rp = rp->l_next
        )
        if (rp->l_cmd) hascmds = TRUE;

    if (dotouch && hascmds) 
    {
        touch(np);
    }
    else
    {
        setmacro("@", np->n_name);  /* NOTE: *not* dollar() */
        setdmacros(np,qdp);
        if (lp) docmds1(np, lp);    /* lp set if doing a :: rule */
        else docmds(np);
    }
}

/*************************************************************************
|                                                                        |
|   >>>>  make                                                           |
|                                                                        |
|   recursive routine to make a target                                   |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
int make(struct name * np, int level)
#else
int make(np, level)
struct name * np;
int level;
#endif

{
    register struct depend *dp;
    register struct line *  lp;
    unsigned long           dtime = 1;
    register struct depend *qdp;
    int                     didsomething = 0;

    if (np->n_flag & N_DONE)
    {
        if ( display ) dodisp(dollar(np->n_name),np->n_time);
        return 0;
    }

    if (!np->n_time)
        searchtime(np);             /*  Gets modtime of this file  */

    if ( display ) dodisp(dollar(np->n_name),np->n_time);

    for (lp = np->n_line; lp; lp = lp->l_next)
        if (lp->l_cmd) break;
    if (!lp) dyndep(np);

    if (!(np->n_flag & N_TARG) && np->n_time == 0L)
        fatal(MSG[66], dollar(np->n_name)); /* Don't know how to make %s */ 

    for (qdp = (struct depend *)0, lp = np->n_line; lp; lp = lp->l_next)
    {
        for (dp = lp->l_dep; dp; dp = dp->d_next)
        {
            make(dp->d_name, level+1);
            if (np->n_time < dp->d_name->n_time)
                qdp = newdep(dp->d_name, qdp);
            if (dtime < dp->d_name->n_time) dtime = dp->d_name->n_time; 
        }
        if (!quest && (np->n_flag & N_DOUBLE) && ((np->n_time < dtime) || all))
        {
            make1(np, lp, qdp);     /* free()'s qdp */
            dtime = 1;
            qdp = (struct depend *)0;
            didsomething++;
        }
    }

    np->n_flag |= N_DONE;

    if (quest)
    {
        unsigned long t;
        t = np->n_time;
        np->n_time = curtime();
        cleardynflag(np);
        return t < dtime;
    }
    else if (((np->n_time < dtime) || all) && !(np->n_flag & N_DOUBLE))
    {
        make1(np, (struct line *)0, qdp);
        if (confirm)
            searchtime(np);
        else
        {
            np->n_time = curtime();
            np->n_flag &= ~N_TSNAP;
        }
    }
    else if (level == 0 && !didsomething)
        printf(MSG[67], myname, dollar(np->n_name));
    cleardynflag(np);
    return 0;
}

/*************************************************************************
|                                                                        |
|   >>>>  searchtime                                                     |
|                                                                        |
|   search defined path for file                                         |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
VOID searchtime(struct name * np)
#else
VOID searchtime(np)
struct name * np;
#endif

{
    char *                  p = np->n_orig;
    register struct path *  pp;
    char *                  q; 
    int                     len;
    char                    delim[2];


    if (np->n_name != p)            /* done already */
    {
        modtime(np);
        return;
    }

    while (*p)                      /* eliminate absolute paths */
    {
#ifdef NIX
        if (*p == '/')
#endif
#ifdef VMS
        if ((*p == ':') || (*p == '[') || (*p == ']'))
#endif
#ifdef PAMDOS
        if ((*p == ':') || (*p == '\\'))
#endif
#ifdef PAMOS2
        if ((*p == ':') || (*p == '\\'))
#endif
        {
            modtime(np);
            return;
        }
        p++;
    }

    q = suffix(np->n_orig);
    for (pp = pathhead; pp; pp = pp->p_next)
        if (!strcmp(q,pp->p_ext)) break;

    if (!pp)                        /* no path for this extension */
    {
        modtime(np);
        return;
    }

    len = strlen(q = pp->p_path);
    delim[0] = delim[1] = '\0';
    if (len)
    {
#ifdef NIX
        if (q[len - 1] != '/') len++, delim[0] = '/';
#endif
#ifdef PAMDOS
        if (q[len - 1] != '\\') len++, delim[0] = '\\';
#endif
#ifdef PAMOS2
        if (q[len - 1] != '\\') len++, delim[0] = '\\';
#endif
    }

    len += strlen(np->n_orig) + 1;
    if (0 == (np->n_name = malloc(len))) fatal(MSG[68]); 
    q = psa(np->n_name,q);
    q = psa(q,delim);
    q = psa(q,np->n_orig);

    modtime(np);
}

